package com.yuanbao.common.utils;

import cn.hutool.json.JSONUtil;
import com.yuanbao.base.request.Request;
import com.yuanbao.base.response.Message;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;

/**
 * @author wangjinliang
 */
public final class RequestLogUtils {
    private static Logger LOGGER = LoggerFactory.getLogger(RequestLogUtils.class);

    private RequestLogUtils() {
    }

    public static void logRequestAndResponse(HttpServletRequest request, Object[] args, Object result) {
        String requestId = "req_" + System.currentTimeMillis();
        logRequest(request, requestId, args);
        logResponse(requestId, result);
    }

    private static void logRequest(HttpServletRequest request, String requestId, Object[] args) {
        String method = request.getMethod();
        Object bodyObj = null;
        if (Objects.nonNull(args) && ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method))) {
            for (Object arg : args) {
                if (arg instanceof Request) {
                    bodyObj = arg;
                    break;
                }
            }
        }
        StringBuilder requestLog = new StringBuilder();
        String path = request.getServletPath();
        String params = CommonUtils.getParams(request).toString();
        String body = stringifyBody(bodyObj);
        requestLog.append("reqId=>").append(requestId).append(";");
        requestLog.append("method=>").append(method).append(";");
        requestLog.append("path=>").append(path).append(";");
        requestLog.append("params=>").append(params).append(";");
        requestLog.append("body=>").append(body).append(";");
        LOGGER.info(requestLog.toString());
    }

    private static String stringifyBody(Object data) {
        if (data == null) {
            return "";
        }

        String result;
        if (data instanceof List) {
            List list = (List) data;
            StringBuilder sb = new StringBuilder("{");
            for (Object e : list) {
                sb.append(ToStringBuilder.reflectionToString(e, ToStringStyle.SHORT_PREFIX_STYLE)).append(",");
            }
            sb.append("}");
            result = sb.toString();
        } else {
            result = ToStringBuilder.reflectionToString(data, ToStringStyle.SHORT_PREFIX_STYLE);
        }
        return result;
    }

    private static void logResponse(String requestId, Object result) {
        StringBuilder responseLog = new StringBuilder();
        String data;
        if (result instanceof Message) {
            Message message = (Message) result;
            if (StringUtils.isEmpty(message.getMessage())) {
                data = "code=" + message.getCode() + "," + stringifyBody(message.getData());
            } else {
                data = "code=" + message.getCode() + "," + "errMsg=" + message.getMessage();
            }
        } else {
            data = Objects.nonNull(result) ? JSONUtil.toJsonStr(result) : "";
        }
        responseLog.append("reqId=>").append(requestId).append(";");
        responseLog.append("return=>").append(data).append(";");
        LOGGER.info(responseLog.toString());
    }
}
